Смещение встроенных элементов при выделении жирным шрифтом при наведении

160

Я создал горизонтальное меню, используя списки HTML и CSS. Все работает как надо, кроме случаев, когда вы наводите курсор мыши на ссылки. Видите ли, я создал состояние полужирного наведения для ссылок, и теперь ссылки меню меняются из-за разницы в полужирном размере.

Я столкнулся с той же проблемой, что и этот пост SitePoint. Однако у поста нет правильного решения. Я искал везде решение и не могу его найти. Конечно, я не могу быть единственным, кто пытается это сделать.

У кого-нибудь есть какие-либо идеи?

PS: я не знаю ширину текста в пунктах меню, поэтому я не могу просто установить ширину элементов li.

.nav { margin: 0; padding: 0; }
.nav li { 
    list-style: none; 
    display: inline; 
    border-left: #ffffff 1px solid; 
}
.nav li a:link, .nav li a:visited { 
    text-decoration: none; 
    color: #000; 
    margin-left: 8px; 
    margin-right: 5px; 
}
.nav li a:hover{ 
    text-decoration: none; 
    font-weight: bold; 
}
.nav li.first { border: none; }
<ul class="nav">
    <li class="first"><a href="#">item 0</a></li>
    <li><a href="#">item 1</a></li>
    <li><a href="#">item 2</a></li>
    <li><a href="#">item 3</a></li>
    <li><a href="#">item 4</a></li>
</ul>
Теги:
hover
text-size

23 ответа

330
Лучший ответ

li {
    display: inline-block;
    font-size: 0;
}
li a {
    display:inline-block;
    text-align:center;
    font: normal 16px Arial;
    text-transform: uppercase;
}
a:hover {
    font-weight:bold;
}
a::after {
    display: block;
    content: attr(title);
    font-weight: bold;
    height: 0;
    overflow: hidden;
    visibility: hidden;
}
<ul>
    <li><a href="#" title="height">height</a></li>
    <li><a href="#" title="icon">icon</a></li>
    <li><a href="#" title="left">left</a></li>
    <li><a href="#" title="letter-spacing">letter-spacing</a></li>
    <li><a href="#" title="line-height">line-height</a></li>
</ul>

Проверьте рабочий пример на JSfiddle. Идея состоит в том, чтобы зарезервировать место для содержимого, выделенного жирным шрифтом (или любого :hover стиля :hover), в псевдоэлементе :after и использовать тег title в качестве источника содержимого.

  • 17
    Отлично! Он работает для <a> даже без использования ul, хотя я бы использовал другой атрибут, например data-text, вместо title.
  • 5
    Это решение работает, но лучше, когда вы добавляете margin-top: -1px к :after чтобы избежать создания пространства высотой 1px.
Показать ещё 8 комментариев
31

Скомпрометированное решение - подделать жирный шрифт с помощью text-shadow, например:

тень текста: 0 0 0.01px черный;

Для лучшего сравнения я создал эти примеры:

a, li {
  color: black;
  text-decoration: none;
  font: 18px sans-serif;
  letter-spacing: 0.03em;
}
li {
  display: inline-block;
  margin-right: 20px;
  color: gray;
  font-size: 0.7em;
}
.bold-x1 a.hover:hover,
.bold-x1 a:not(.hover) {
  text-shadow: 0 0 .01px black;
}
.bold-x2 a.hover:hover,
.bold-x2 a:not(.hover){
  text-shadow: 0 0 .01px black, 0 0 .01px black;
}
.bold-x3 a.hover:hover,
.bold-x3 a:not(.hover){
  text-shadow: 0 0 .01px black, 0 0 .01px black, 0 0 .01px black;
}
.bold-native a.hover:hover,
.bold-native a:not(.hover){
  font-weight: bold;
}

.bold-native li:nth-child(4),
.bold-native li:nth-child(5){
 margin-left: -6px;
 letter-spacing: 0.01em;
}
<ul class="bold-x1">
  <li><a class="hover" href="#">Home</a></li>
  <li><a class="hover" href="#">Products</a></li>
  <li><a href="#">Contact</a></li>
  <li><a href="#">About</a></li>
  <li>Bold (text-shadow x1)</li>
</ul>
<ul class="bold-x2">
  <li><a class="hover" href="#">Home</a></li>
  <li><a class="hover" href="#">Products</a></li>
  <li><a href="#">Contact</a></li>
  <li><a href="#">About</a></li>
  <li>Extra Bold (text-shadow x2)</li>
</ul>
<ul class="bold-native">
  <li><a class="hover" href="#">Home</a></li>
  <li><a class="hover" href="#">Products</a></li>
  <li><a href="#">Contact</a></li>
  <li><a href="#">About</a></li>
  <li>Bold (native)</li>
</ul>
<ul class="bold-x3">
  <li><a class="hover" href="#">Home</a></li>
  <li><a class="hover" href="#">Products</a></li>
  <li><a href="#">Contact</a></li>
  <li><a href="#">About</a></li>
  <li>Black (text-shadow x3)</li>
</ul>

Переход к очень низкому значению text-shadow для blur-radius сделает эффект размытия не столь очевидным.

В общем, чем больше ваша повторяющаяся text-shadow тем смелее будет текст, но в то же время он теряет первоначальную форму букв.

Я должен предупредить вас, что установка blur-radius фракциям не будет отображаться одинаково во всех браузерах! Safari, например, нужны большие значения, чтобы отобразить его так же, как в Chrome.

  • 3
    Это даже хуже, чем другие смелые решения, рассчитанные браузером, и его следует избегать
28

Если вы не можете установить ширину, это означает, что ширина будет изменяться по мере того, как текст станет полужирным. Невозможно избежать этого, кроме как с помощью компромиссов, таких как изменение отступов/полей для каждого состояния.

  • 2
    +1 как говорит Андрей, жирный шрифт шире. Факт жизни. Даже исправьте ширину пунктов меню, чтобы избежать этого или жить с ним (пересчет отступов неточен и подвержен ошибкам).
  • 0
    Да, я склонен избегать эффекта жирного наведения мыши по этой причине.
Показать ещё 2 комментария
19

Другая идея заключается в использовании letter-spacing

a {
  letter-spacing: 0.05px
}

a:hover, a:focus {
  font-weight: bold;
  letter-spacing: 0
}
17

Одна строка в jquery:

$('ul.nav li a').each(function(){
    $(this).parent().width($(this).width() + 4);
});

изменить: Хотя это может привести к решению, следует упомянуть, что он не работает в сочетании с кодом в исходном сообщении. "display: inline" необходимо заменить плавающими параметрами для установки ширины, и это горизонтальное меню будет работать по назначению.

  • 0
    Можете ли вы сделать это для всех ссылок на странице? То есть заменяет ul.nav li a a произведениями?
  • 2
    Этот вопрос не был помечен с помощью JS, не говоря уже о jQuery. Пожалуйста, не размещайте ненужные решения.
Показать ещё 3 комментария
5

Я просто решил проблему с "теневым" решением. Это кажется самым простым и эффективным.

nav.mainMenu ul li > a:hover, nav.mainMenu ul li.active > a {
    text-shadow:0 0 1px white;
}

Нет необходимости повторять тень три раза (результат для меня был одинаковым).

  • 0
    Это даже хуже, чем другие смелые решения, рассчитанные браузером, и его следует избегать
5

Вы можете использовать somehting как

<ul>
   <li><a href="#">Some text<span><br />Some text</span></a></li>
</ul>

а затем в вашем CSS просто установите содержание диапазона жирным шрифтом и спрячьте его с видимостью: скрытым, чтобы он сохранял свои размеры. Затем вы можете настроить поля следующих элементов, чтобы они соответствовали требованиям.

Я не уверен, что этот подход оптимизирован для SEO.

  • 0
    Это также не удобно для разработчиков
4

Решение CSS3 - экспериментальное

(фальшивая смелость)

Мысль поделиться другим решением, которое никто не предложил здесь. Там будет свойство text-stroke, которое будет удобно для этого.

p span:hover {
  -webkit-text-stroke: 1px black;
}
<p>Some stuff, <span>hover this,</span> it cool</p>

Здесь я нацеливаю текст внутри тега span, и мы поглаживаем его пикселем с black, который будет имитировать стиль bold для этого конкретного текста.

Обратите внимание, что это свойство не поддерживается широко (на данный момент написано), только Chrome и Firefox, похоже, поддерживают это. Для получения дополнительной информации о поддержке браузера для text-stroke вы можете обратиться к CanIUse.


Для обмена некоторыми дополнительными материалами вы можете использовать -webkit-text-stroke-width: 1px;, если вы не хотите устанавливать color для вашего штриха.

4

У меня была проблема, похожая на вашу. Я хотел, чтобы мои ссылки были смелыми, когда вы наводили на них курсор, но не только в меню, но и в тексте. Как вы догадываетесь, это будет реальная задача, определяющая все разные ширины. Решение довольно просто:

Создайте поле, содержащее текст ссылки, выделенным жирным шрифтом, но цветным, как ваш фон, и ваша реальная ссылка над ним. Вот пример из моей страницы:

CSS

.hypo { font-weight: bold; color: #FFFFE0; position: static; z-index: 0; }
.hyper { position: absolute; z-index: 1; }

Конечно, вам нужно заменить # FFFFE0 на цвет фона вашей страницы. Z-индексы не кажутся необходимыми, но я все равно их помещаю (поскольку элемент "hypo" будет возникать после элемента "hyper" в HTML-коде). Теперь, чтобы добавить ссылку на вашу страницу, включите следующее:

HTML:

You can find foo <a href="http://bar.com" class="hyper">here</a><span class="hypo">here</span>

Второе "здесь" будет невидимым и скрытым ниже вашей ссылки. Поскольку это статическая коробка с ваш текст ссылки выделен жирным шрифтом, остальная часть вашего текста больше не будет меняться, поскольку она уже сдвинута, прежде чем навести курсор на ссылку.

Надеюсь, я смог помочь:).

Так долго

2

Вы можете работать с свойством "margin":

li a {
  margin: 0px 5px 0px 5px;
}

li a:hover {
  margin: 0;
  font-weight: bold;
}

Просто убедитесь, что левое и правое поле достаточно большие, поэтому дополнительное пространство может содержать жирный текст. Для длинных слов вы можете выбрать разные поля. Это просто еще один способ обхода, но я сделал для меня работу.

  • 0
    Я использовал похожее решение, но для меня - просто добавив 'margin: 0 -2px' к стилю наведения (и не добавляя ничего к обычному стилю) - отлично работало.
  • 4
    Это не работает, если есть какая-либо изменчивость в вашей длине строки
2

Я бы посоветовал переключение шрифтов (°) на зависание. В этом случае только элементы меню перемещаются немного, но я видел случаи, когда полный абзац переформатирован, потому что расширение вызывает дополнительный перенос слов. Вы не хотите, чтобы это произошло, когда единственное, что вы делаете, - это перемещать курсор; если вы ничего не делаете, макет страницы не должен меняться.

Смещение также может происходить при переключении между нормальным и курсивом. Я бы попробовал изменить цвета или переключить подчеркивание, если у вас есть место под текстом. (подчеркивание должно оставаться прозрачным с нижней границы)

Я бы попробовал, если бы использовал шрифты для моего класса Form Design: -)

(°) Шрифт слова часто используется неправильно. "Verdana" - это шрифт, "Verdana normal" и "Verdana bold" - это разные шрифты одного и того же шрифта.

1

Мне нравится использовать текстовую тень. Тем более, что вы можете использовать переходы для анимации текстовой тени.

Все, что вам действительно нужно:

a {
  transition: text-shadow 1s;
}
a:hover {
  text-shadow: 1px 0 black;
}

Для полной навигации проверьте этот jsfiddle: https://jsfiddle.net/831r3yrb/

Поддержка браузера и дополнительная информация о теневой тени: http://www.w3schools.com/cssref/css3_pr_text-shadow.asp

  • 0
    Это хорошо работает с использованием переходов. Отличное альтернативное решение.
0

Я использую решение для тени текста, как некоторые другие, упомянутые здесь:

text-shadow: 0 0 0.01px;

разница в том, что я не указываю цвет тени, поэтому это решение универсально для всех цветов шрифта.

0

ul {
  list-style-marker: none;
  padding: 0;
}

li {
  display: inline-block;
}

li + li {
  margin-left: 1em;
}

a {
  display: block;
  position: relative;
  text-align: center;
}

a:before, a:after {
  content: attr(aria-label);
  text-decoration: inherit;
}

a:before {
  font-weight: bold;
  visibility: hidden;
}

a:after {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

a:hover:before {
  visibility: visible;
}

a:hover:after {
  display: none;
}
<ul>
  <li>
    <a href="" aria-label="Long-long-long"></a>
  </li><li>
    <a href="" aria-label="or"></a>
  </li><li>
    <a href="" aria-label="Short"></a>
  </li><li>
    <a href="" aria-label="Links"></a>
  </li><li>
    <a href="" aria-label="Here"></a>
  </li>
</ul>
0

Я объединил кучу описанных выше методов, чтобы обеспечить что-то, что не полностью сосать с выключенным js, и даже лучше с небольшим количеством jQuery. Теперь, когда браузер поддерживает субпиксельное письмо-интервал, он действительно приятен в использовании.

jQuery(document).ready(function($) {
  $('.nav a').each(function(){
      $(this).clone().addClass('hoverclone').fadeTo(0,0).insertAfter($(this));
    var regular = $(this);
    var hoverclone = $(this).next('.hoverclone');
    regular.parent().not('.current_page_item').hover(function(){
      regular.filter(':not(:animated)').fadeTo(200,0);
      hoverclone.fadeTo(150,1);
    }, function(){
      regular.fadeTo(150,1);
      hoverclone.filter(':not(:animated)').fadeTo(250,0);
    });
  });
});
ul {
  font:normal 20px Arial;
  text-align: center;
}
li, a {
  display:inline-block;
  text-align:center;
}
a {
  padding:4px 8px;
  text-decoration:none;
  color: #555;
}

.nav a {
  letter-spacing: 0.53px; /* adjust this value per font */
}
.nav .current_page_item a,
.nav a:hover {
  font-weight: bold;
  letter-spacing: 0px;
}
.nav li {
  position: relative;
}
.nav a.hoverclone {
  position: absolute;
  top:0;
  left: 0;
  white-space: nowrap;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="nav">
  <li><a href="#">Item 1</a></li>
  <li><a href="#">Item 2</a></li>
  <li class="current_page_item"><a  href="#">Item 3</a></li>
  <li><a href="#">Item 4</a></li>
  <li><a href="#">Item 5</a></li>
</ul>
0

Не очень элегантное решение, но "работает":

a
{
    color: #fff;
}

a:hover
{
    text-shadow: -1px 0 #fff, 0 1px #fff, 1px 0 #fff, 0 -1px #fff;
}
0

Как насчет этого? Бесплатное решение javascript - CSS3.

http://jsfiddle.net/u1aks77x/1/

ul{}
li{float:left; list-style-type:none; }
a{position:relative; padding-right: 10px; text-decoration:none;}
a > .l1{}
a:hover > .l1{visibility:hidden;}
a:hover > .l2{display:inline;}
a > .l2{position: absolute; left:0; font-weight:bold; display:none;}

<ul>
  <li><a href="/" title="Home"><span class="l1">Home</span><span class="l2">Home</span></a></li>
  <li><a href="/" title="Contact"><span class="l1">Contact</span><span class="l2">Contact</span></a></li>
  <li><a href="/" title="Sitemap"><span class="l1">Sitemap</span><span class="l2">Sitemap</span></a></li>
</ul>
  • 1
    Это довольно много лишней разметки и CSS, чтобы исправить проблему ... Это не разработчик, SEO или будущее
0

Это решение, которое я предпочитаю. Это требует немного JS, но вам не нужно, чтобы ваше свойство title было таким же, и ваш CSS может оставаться очень простым.

$('ul a').each(function() {
  $(this).css({
    'padding-left': 0,
    'padding-right': 0,
    'width': $(this).outerWidth()
  });
});
li, a { display: inline-block; }
a {
  padding-left: 10px;
  padding-right: 10px;
  text-align: center; /* optional, smoother */
}
a:hover { font-weight: bold; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul>
  <li><a href="#">item 1</a></li>
  <li><a href="#">item 2</a></li>
  <li><a href="#">item 3</a></li>
</ul>
0

Я действительно не могу этого вынести, когда кто-то говорит вам не делать что-то таким образом, когда есть простое решение проблемы. Я не уверен в элементах li, но я просто исправил ту же проблему. У меня есть меню, состоящее из тегов div.

Просто установите тег div как "display: inline-block". Inline, чтобы они сидели рядом друг с другом и блокировались, чтобы вы могли установить ширину. Просто установите ширину, достаточную для размещения выделенного полужирным шрифтом, и выравнивание текста по центру.

(Примечание. Кажется, что он удаляет мой html [ниже], но каждый элемент меню имеет тег div, обернутый вокруг него с помощью идентификатора corprendinging и имени класса SearchBar_Cateogory, то есть: <div id="ROS_SearchSermons" class="SearchBar_Category">

HTML (У меня были привязанные теги, обернутые вокруг каждого элемента меню, но я не мог представить их как новый пользователь)

<div id="ROS_SearchSermons" class="SearchBar_Cateogry bold">Sermons</div>|
<div id="ROS_SearchIllustrations" class="SearchBar_Cateogry">Illustrations</div>|
<div id="ROS_SearchVideos" class="SearchBar_Cateogry">Videos</div>|
<div id="ROS_SearchPowerPoints" class="SearchBar_Cateogry">PowerPoints</div>|
<div id="ROS_SearchScripture" class="SearchBar_Cateogry">Scripture</div>|

CSS

#ROS_SearchSermons { width: 75px; }
#ROS_SearchIllustrations { width: 90px; }
#ROS_SearchVideos { width: 55px; }
#ROS_SearchPowerPoints { width: 90px; }
#ROS_SearchScripture { width: 70px; }

.SearchBar_Cateogry
{
    display: inline-block;
    text-align:center;
}
  • 1
    Это использует фиксированную ширину, точно так же, как заданный OP НЕ имеет место. Таким образом, этот ответ не отвечает на задаваемый вопрос.
-2

попробуй это:

.nav {
  font-family: monospace;
}
  • 0
    Как это что-то изменит?
  • 0
    @MiXT4PE MiXT4PE В моноширине символы имеют одинаковый размер обычного или жирного шрифта. размер не изменится
-2

Вы также можете попробовать отрицательные поля, если жирный текст более широк, чем обычный. (не всегда) Поэтому идея состоит в том, чтобы использовать классы вместо стиля: hover.

JQuery

 $(".nav-main .navbar-collapse > ul > li > a").hover(function() {
    var originalWidth = $(this).outerWidth();

    $(this).parent().addClass("hover");
    $(this).css({
       "margin-left": -(($(this).outerWidth() - originalWidth) / 2),
       "margin-right": -(($(this).outerWidth() - originalWidth) / 2)
    });
 },
 function() {
    $(this).removeAttr("style");
    $(this).parent().removeClass("hover");
 });

CSS

ul > li > a {
    font-style: normal;
}

ul > li > a.hover {
    font-style: bold;
}

Я надеюсь, что смогу помочь!

  • 1
    Пожалуйста, не публикуйте ответы на языках, отличных от отмеченных. Это не отвечает на задаваемый вопрос
-2

Если вы не прочь использовать Javascript, вы можете установить правильную ширину после отображения страницы. Вот как я это сделал (используя Prototype):

$$('ul.nav li').each(this.setProperWidth);

setProperWidth: function(li)
{
  // Prototype getWidth() includes padding, so we 
  // have to subtract that when we set the width.
  var paddingLeft = li.getStyle('padding-left'),
      paddingRight = li.getStyle('padding-right');

  // Cut out the 'px' at the end of each padding
  paddingLeft = paddingLeft.substring(0,paddingLeft.length-2);
  paddingRight = paddingRight.substring(0,paddingRight.length-2);

  // Make the li bold, set the width, then unbold it
  li.setStyle({ fontWeight: 'bold' });
  li.setStyle({ width: (li.getWidth() - paddingLeft - paddingRight) + 'px'});
  li.setStyle({ fontWeight: 'normal', textAlign: 'center' });
}
  • 0
    Javascript не был отмечен в вопросе, не говоря уже о jQuery. Пожалуйста, продолжайте отвечать, используя языки, отмеченные в вопросе
-4

вот идея для плагина jquery:

for all of the elements that you want bold mouse-over:
    - on mouseover:
        - calculate the width W and center C of the element
        - copy the element and hide the original with visibility:hidden (so it still takes up the same space)
        - make the text of the copied element bold and calculate the new width W2
        - position the element absolute left at C-(W2/2)

Вы можете легко расширить его и на высоту, позволяя слегка увеличить размер шрифта при наведении курсора мыши, не беспокоясь о переходе контента.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню